package com.lc.learn.fileana.service.impl;

import com.aspose.words.Document;
import com.aspose.words.ImageSaveOptions;
import com.aspose.words.SaveFormat;
import com.lc.learn.fileana.service.DocxToImgService;
import com.study.common.constant.LocalConstant;
import org.apache.http.entity.ContentType;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Date:   2024/1/8
 * author: LiChuang
 */
@Service
public class DocxToImgServiceImpl implements DocxToImgService {

    @Value("${contract.path}")
    private String path;

    @Value("${contract.template}")
    private String template;

    @Override
    public String fillContractContent(Map<String, String> map) {
        try {
            this.getContractKeys(map);
            // 替换word文件内容中的关键字
            InputStream is = Files.newInputStream(Paths.get(path + template));
            XWPFDocument docx = new XWPFDocument(is);
            List<XWPFParagraph> paragraphList = docx.getParagraphs();
            for (XWPFParagraph paragraph : paragraphList) {
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    if (map.get(run.toString().trim()) != null) {
                        run.setText(map.get(run.toString().trim()), 0);
                    }
                }
            }
            // 替换word文件表格中的关键字
            List<XWPFTable> tables = docx.getTables();
            for (XWPFTable table : tables) {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        for (XWPFParagraph paragraph : cell.getParagraphs()) {
                            for (XWPFRun run : paragraph.getRuns()) {
                                if (map.get(run.toString().trim()) != null) {
                                    run.setText(map.get(run.toString().trim()), 0);
                                    run.setFontFamily("宋体", XWPFRun.FontCharRange.cs);
                                }
                            }
                        }
                    }
                }
            }
            String fileName = path + System.currentTimeMillis() + ".docx";
            OutputStream outputStream = Files.newOutputStream(Paths.get(fileName));
            // 将填充后的合同文件再上传到服务器
            docx.write(outputStream);
            return fileName;
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    private void getContractKeys(Map<String, String> map) {
        // TODO 查询自己在docx文件中写入的关键字信息
    }

    @Override
    public MultipartFile wordToImg(String fileName) {
        {
            try {
                // word转图片
                Document document = new Document(Files.newInputStream(Paths.get(fileName)));
                ImageSaveOptions options = new ImageSaveOptions(SaveFormat.PNG);
                options.setPrettyFormat(true);
                options.setUseAntiAliasing(true);
                options.setUseHighQualityRendering(true);
                options.setResolution(200F);// 设置分辨率
                List<BufferedImage> imageList = new ArrayList<>();
                for (int i = 0; i < document.getPageCount(); i++) {
                    OutputStream output = new ByteArrayOutputStream();
                    options.setPageIndex(i);
                    document.save(output, options);
                    ImageInputStream imageInputStream = ImageIO.createImageInputStream(parse(output));
                    imageList.add(ImageIO.read(imageInputStream));
                }
                // 图片垂直拼接，写入服务器
                BufferedImage bufferedImage = mergeImage(false, imageList);
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                ImageIO.write(bufferedImage, "png", os);
                // 将替换关键字后的word文件从服务器删除
                boolean delete = new File(fileName).delete();
                String imageName = LocalConstant.CONTRACT_PRE + System.currentTimeMillis() + ".png";
                return new MockMultipartFile(imageName, imageName, ContentType.APPLICATION_OCTET_STREAM.toString(), new ByteArrayInputStream(os.toByteArray()));
            } catch (Exception e) {
                throw new RuntimeException("合同文档转图片异常");
            }
        }
    }

    /**
     * 去除 lib/aspose-words-15.8.0-jdk16.jar 自身的水印
     * 生成图片的方法封装必须调用该方法，否则生成的图片存在水印
     */
    @PostConstruct
    private void isWordLicense() {
        try {
            String s = "<License><Data><Products><Product>Aspose.Total for Java</Product><Product>Aspose.Words for Java</Product></Products><EditionType>Enterprise</EditionType><SubscriptionExpiry>20991231</SubscriptionExpiry><LicenseExpiry>20991231</LicenseExpiry><SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber></Data><Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature></License>";
            ByteArrayInputStream inputStream = new ByteArrayInputStream(s.getBytes());
            com.aspose.words.License license = new com.aspose.words.License();
            license.setLicense(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 输出流转输入流
     */
    private ByteArrayInputStream parse(OutputStream out) {
        ByteArrayOutputStream arrayOutputStream = (ByteArrayOutputStream) out;
        return new ByteArrayInputStream(arrayOutputStream.toByteArray());
    }

    /**
     * 合并多张图片为一张
     * isHorizontal true-水平合并 false-垂直合并
     */
    private BufferedImage mergeImage(boolean isHorizontal, List<BufferedImage> imgList) {
        // 生成新图片
        BufferedImage destImage;
        // 计算新图片的长和高
        int allw = 0, allh = 0, allwMax = 0, allhMax = 0;
        // 获取总长、总宽、最长、最宽
        for (int i = 0; i < imgList.size(); i++) {
            BufferedImage img = imgList.get(i);
            allw += img.getWidth();
            if (imgList.size() != i + 1) {
                allh += img.getHeight() + 5;
            } else {
                allh += img.getHeight();
            }
            if (img.getWidth() > allwMax) {
                allwMax = img.getWidth();
            }
            if (img.getHeight() > allhMax) {
                allhMax = img.getHeight();
            }
        }
        // 创建新图片
        if (isHorizontal) {
            destImage = new BufferedImage(allw, allhMax, BufferedImage.TYPE_INT_RGB);
        } else {
            destImage = new BufferedImage(allwMax, allh, BufferedImage.TYPE_INT_RGB);
        }
        Graphics2D g2 = (Graphics2D) destImage.getGraphics();
        g2.setBackground(Color.LIGHT_GRAY);
        g2.clearRect(0, 0, allw, allh);
        g2.setPaint(Color.RED);

        // 合并所有子图片到新图片
        int wx = 0, wy = 0;
        for (BufferedImage img : imgList) {
            int w1 = img.getWidth();
            int h1 = img.getHeight();
            // 从图片中读取RGB
            int[] ImageArrayOne = new int[w1 * h1];
            ImageArrayOne = img.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 逐行扫描图像中各个像素的RGB到数组中
            if (isHorizontal) { // 水平方向合并
                destImage.setRGB(wx, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
            } else { // 垂直方向合并
                destImage.setRGB(0, wy, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
            }
            wx += w1;
            wy += h1 + 5;
        }
        return destImage;
    }

}
